﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using INI;
using System.Data;
/**************************
 * zebra printer dimensition relation:
 * 1000dot = 8.2mm (300dpi)
 * dots=DPI * length(mm)/2.54
 * 
 * ************************/
namespace ZebraClass
{


    #region----------------标签内文本条目和框框结构的定义---------------
    public struct LabelText
    {
        public string Name; //标签上一个文本框的名字，条码内容不包括这部分
        public string Text;//标签上一个文本框的内容，就是条码的内容
        public int RotateDegree; //标签上文本条目的旋转角度

        public int NamePosX;
        public int NamePosY;
        public int NameWidth; 
        public int NameHeight;
        public string NameFontCN; //JM20130415 add

        public int TextPosX;
        public int TextPosY;
        public int TextWidth;     //JM20130415 add
        public int TextHeight;    //JM20130415 add
        public string TextFontCN; //JM20130415 add

        public bool PrintBar;
        public bool PrintName;
        public int BarType;

        public int BarPosX;
        public int BarPosY;
        public int BarWidth;
        public int BarHeight;
        public double BarRatio;
        public bool PrintCode;
        public bool PrintAboveBarCode;
        public bool PrintText;
        public bool NameTextTogether;

        public string NameFont; //JM20131206 add
        public string TextFont; //JM20131206 add

    }
    public struct LabelBox
    {
        public string Description;
        public int PosX;
        public int PosY;
        public int Width;
        public int Height;
        public int Thick;
        public int Corner;

    }
    #endregion

    /// <summary>斑马打印机类
    /// 创建打印机后，将从Zebra.ini中读取斑马打印机的一些配置，然后创建一个private标签，并读取Label.ini的配置至该标签中。
    /// 该标签的模板不能通过程序更改，只能更改Label.ini的配置。
    /// 该标签中文本条目的值可以直接在PrintLabel()里面加入，就可以打印出标签了
    /// </summary>
    public class ZebraPrinter
    {

        #region<<<------------------公有变量定义------------->>>
        public string PortName;
        public int Braud;
        #endregion

        #region<<<---------------------私有变量定义---------------->>>
        private System.IO.Ports.SerialPort CommPort;
        private string OutPutCode;
        private double XMax_in_mm;
        private double YMax_in_mm;
        private double XStart_in_mm;
        private double YStart_in_mm;
        private int XMax_in_dots;
        private int YMax_in_dots;
        private int XStart_in_dots;
        private int YStart_in_dots;
        private int DPI;    //printer's DPI, dots per inch
        private double DPmm;//dots per milli meter

        public  ZebraLabel myLabel;

        private string iniZebra = Application.StartupPath.TrimEnd('\\') + "\\Zebra.ini";
        private string iniLabel = Application.StartupPath.TrimEnd('\\') + "\\Label.ini";
        #endregion

        #region<<<---------------------构造函数--------------------------->>>

        /// <summary>构造函数，读取Zebra.ini配置，读取Label.ini来创建标签
        /// </summary>
        public ZebraPrinter()
        {
            ReadZebraINI();
            CommPort = new System.IO.Ports.SerialPort(PortName, Braud, System.IO.Ports.Parity.None, 8, System.IO.Ports.StopBits.One);
            CommPort.PortName = PortName;
            XMax_in_dots = calDots(Convert.ToDouble(XMax_in_mm));
            YMax_in_dots = calDots(Convert.ToDouble(YMax_in_mm));
            DPmm = Convert.ToDouble(DPI) / 25.4;

            NewLabelFromINI();
        }

        #endregion

        #region<<<----------------外部可调用的打印功能和写入Label.INI功能----------------->>>

        /// <summary>按顺序将字串数组TextContent[]中的各个元素赋值给标签的文本条目，输入的字串数组TextContent[]可以比标签中文本条目数少，但是不能多
        /// </summary>
        /// <param name="TextContent">字串数组，顺序对应着Label.ini中的各个[TEXT*]文本条目的内容</param>
        public void PrintLabel(string[] TextContent)
        {
            PrintLabel(TextContent, new Int32[0] { }, new Int32[0] { });
        }

        /// <summary> 按顺序将字串数组TextContent[]中的各个元素赋值给标签的文本条目，可以允许某些文本条目或框框不打印
        /// </summary>
        /// <param name="TextContent">和Label.ini中各个文本条目顺序一样的数组</param>
        /// <param name="ItemNotPrint">哪些条目不打印</param>
        /// <param name="BoxNotPrint">哪些框框不打印</param>
        public void PrintLabel(string[] TextContent, Int32[] ItemNotPrint, Int32[] BoxNotPrint)
        {
            int i = 0;

            myLabel.ID_All_ReadFromINI();

            if (TextContent.Length > myLabel.lbText.Length)
            {
                MessageBox.Show("需要打印的条目数量多于Label.ini配置中的文本条目数，无法打印");
                return;
            }
            //foreach (string str in TextContent) myLabel.lbText[i++].Text = str;

            for (i = 0; i < myLabel.lbText.Length; i++)
            {
                myLabel.lbText[i].Text = TextContent [i];
                if (ItemNotPrint.Contains<Int32>(i)) continue;
                objPrintFontByPosition(myLabel.lbText[i]);
            }
            for (i = 0; i < myLabel.lbBox.Length; i++)
            {
                if (BoxNotPrint.Contains<Int32>(i)) continue;
                objPrintBoxByPosition(myLabel.lbBox[i]);
            }
            PrintOutPutCodeToComPort();
            //this.WriteLabelINI();
            NewLabelFromINI();
        }

        #endregion

        #region<<<------------------------其他功能函数：CalDots,NewLabelFromINI,PrintOutPutCode,GetRotateCode---------------->>>

        /// <summary>将尺寸转换为dot数
        /// </summary>
        private int calDots(double length_in_mm)
        {
            int iTemp;
            double dTemp;
            dTemp = length_in_mm * DPmm;
            iTemp = Convert.ToInt32(dTemp);
            return iTemp;
        }

        /// <summary>读取Label.ini的配置内容，将配置内容写入新标签myLabel
        /// </summary>
        private void NewLabelFromINI()
        {
            myLabel = new ZebraLabel();
            OutPutCode = "^XA^LH" + XStart_in_dots.ToString() + "," + YStart_in_dots.ToString();
        }

        /// <summary>打开端口，在OutPutCode的结尾加上结尾标志符^XZ，并将OutPutCode输出至端口
        /// </summary>
        public void PrintOutPutCodeToComPort()
        {

 //           MessageBox.Show("PrintCode Called", "DebugMessage");

            if (!CommPort.IsOpen) CommPort.Open();
            CommPort.WriteLine(OutPutCode + "^XZ");
            CommPort.Close();

            //return OutPutCode + "^XZ";
        }
        public void PrintOutPutCodeToComPort(string sOut)
        {

            //           MessageBox.Show("PrintCode Called", "DebugMessage");

            if (!CommPort.IsOpen) CommPort.Open();
            CommPort.WriteLine(sOut  + "^XZ");
            CommPort.Close();

            //return OutPutCode + "^XZ";
        }

        private string GetRotateCode(int degree)
        {
            string RotateCode;//N--Normal, don't rotate; R--90 rotate(clockwise); I: inverted 180; B--270 rotate; 
            switch (degree)
            {
                case 0: RotateCode = "N"; break;
                case 90: RotateCode = "R"; break;
                case 180: RotateCode = "I"; break;
                case 270: RotateCode = "B"; break;
                default: RotateCode = "N"; break;
            }
            return RotateCode;
        }

        /// <summary>检查字符串里面是否含有汉字
        /// </summary>
        private bool IsGBCode(string word)
        {
            int i = 0;
            byte byte1;
            byte byte2;
            byte[] bytes = Encoding.GetEncoding("GB2312").GetBytes(word);

            if (bytes.Length <= 1) return false; // if there is only one byte, it is ASCII code or other code

            while (i < bytes.Length - 1)
            {
                byte1 = bytes[i];
                byte2 = bytes[i + 1];
                if (byte1 < 127) { i++; continue; }//是字母
                else { if ((byte1 >= 176 && byte1 <= 247 && byte2 >= 160 && byte2 <= 254)) return true; else return false; }
            }
            return false;
        }
        #endregion

        #region<<<----------INI functions---------->>>

        /// <summary>从Zebra.ini文件读取斑马打印机的配置，包括DPI，波特率，端口号等
        /// </summary>
        public void ReadZebraINI()
        {
            INIClass myINIClass = new INIClass(iniZebra);

            DPI = myINIClass.IniReadValue("Setting", "DPI", 300);

            XMax_in_dots = myINIClass.IniReadValue("Setting", "XMax_in_dots", -1);
            YMax_in_dots = myINIClass.IniReadValue("Setting", "YMax_in_dots", -1);
            XStart_in_dots = myINIClass.IniReadValue("Setting", "XStart_in_dots", -1);
            YStart_in_dots = myINIClass.IniReadValue("Setting", "YStart_in_dots", -1);
            Braud = myINIClass.IniReadValue("Setting", "Braud", 9600);
            PortName = myINIClass.IniReadValue("Setting", "PortName", "COM1");

            XMax_in_mm = myINIClass.IniReadValue("Setting", "XMax_in_mm", 100);
            YMax_in_mm = myINIClass.IniReadValue("Setting", "YMax_in_mm", 100);
            XStart_in_mm = myINIClass.IniReadValue("Setting", "XStart_in_mm", 10);
            YStart_in_mm = myINIClass.IniReadValue("Setting", "YStart_in_mm", 10);

            if (XMax_in_dots < 0) XMax_in_dots = this.calDots(XMax_in_mm);
            if (YMax_in_dots < 0) YMax_in_dots = this.calDots(YMax_in_mm);
            if (XStart_in_dots < 0) XStart_in_dots = this.calDots(XStart_in_mm);
            if (YStart_in_dots < 0) YStart_in_dots = this.calDots(YStart_in_mm);

        }

        /// <summary>将当前配置的内容写入Zebra.ini中，包括DPI，波特率，端口号等
        /// </summary>
        public void WriteZebraINI()
        {
            INIClass myINIClass = new INIClass(iniZebra);

            myINIClass.IniWriteValue("Setting", "DPI", DPI.ToString());

            myINIClass.IniWriteValue("Setting", "XMax_in_dots", XMax_in_dots.ToString());
            myINIClass.IniWriteValue("Setting", "YMax_in_dots", YMax_in_dots.ToString());
            myINIClass.IniWriteValue("Setting", "XStart_in_dots", XStart_in_dots.ToString());
            myINIClass.IniWriteValue("Setting", "YStart_in_dots", YStart_in_dots.ToString());
            myINIClass.IniWriteValue("Setting", "Braud", Braud.ToString());
            myINIClass.IniWriteValue("Setting", "PortName", PortName);

        }

        /// <summary>将标签的配置写入Label.ini中，主要是在程序之初创建Label.ini用。
        /// </summary>
        public void WriteLabelINI()
        {
            myLabel.ID_All_WriteToINI();
        }

        #endregion

        #region <<<---------------在标签上直接写文本条目，直接画框框------------------->>>>
        private void objPrintFontByPosition(LabelText text)
        {
            if (text.NameTextTogether)//如果name和text合并在一起
            {
                if (IsGBCode(text.Name + text.Text)) PrintCharatorByPosition(text.NamePosX, text.NamePosY, text.NameWidth, text.NameHeight, text.Name + text.Text, "Arial Narrow", text.RotateDegree, 0, 0);
                else  PrintFontByPosition(text.NamePosX, text.NamePosY, text.NameWidth, text.NameHeight, text.Name + text.Text, text.RotateDegree,text .NameFont);
            }
            else//如果name和text分开打印
            {
                if (text.PrintName)//如果打印条目的名字
                {
                    if (IsGBCode(text.Name)) PrintCharatorByPosition(text.NamePosX, text.NamePosY, text.NameWidth, text.NameHeight, text.Name, "Arial Narrow", text.RotateDegree, 0, 0);
                    else PrintFontByPosition(text.NamePosX, text.NamePosY, text.NameWidth, text.NameHeight, text.Name, text.RotateDegree,text .NameFont);
                }
                //打印条目的内容
                if (text.PrintText)
                {
                    if (IsGBCode(text.Text)) PrintCharatorByPosition(text.TextPosX, text.TextPosY, text.TextWidth, text.TextHeight, text.Text, "Arial Narrow", text.RotateDegree, 0, 0);
                    else PrintFontByPosition(text.TextPosX, text.TextPosY, text.TextWidth, text.TextHeight, text.Text, text.RotateDegree,text .NameFont );
                }
            }
            //打印条目内容的条码或二维码
            if (text.PrintBar)
            {
                switch (text.BarType)
                {
                    case 1: PrintBarCode39(text.BarPosX, text.BarPosY, text.BarWidth, text.BarRatio, text.BarHeight, text.Text, text.RotateDegree, text.PrintCode, text.PrintAboveBarCode); break;
                    case 2: PrintBarCodeEAN_8(text.BarPosX, text.BarPosY, text.BarWidth, text.BarRatio, text.BarHeight, text.Text, text.RotateDegree, text.PrintCode, text.PrintAboveBarCode); break;
                    case 3: PrintBarCode128(text.BarPosX, text.BarPosY, text.BarWidth, text.BarRatio, text.BarHeight, text.Text, text.RotateDegree, text.PrintCode, text.PrintAboveBarCode); break;
                    case 4: PrintDataMatrix(text.BarPosX, text.BarPosY, text.Text, text.BarHeight, 50, 0); break;
                    case 5: Print2DCode_QR(text.BarPosX, text.BarPosY, text.BarWidth, text.BarRatio, text.BarHeight, text.Text, text.RotateDegree, text.PrintCode, text.PrintAboveBarCode); break;
                    default: break;
                }
            }
        }
        private void objPrintBoxByPosition(LabelBox box)
        {
            PrintGraphBoxByPosition(box.PosX, box.PosY, box.Width, box.Height, box.Thick, box.Corner);
        }

        #endregion

        #region<<<---------------各种在标签上写东西，画框框的功能---------------->>>

        /// <summary>输出一定大小的字体在某个位置
        /// </summary>
        /// <param name="RefrenceX">坐标</param>
        /// <param name="RefrenceY">坐标</param>
        /// <param name="Width_in_Dot">字体的宽度，单位是dots</param>
        /// <param name="Height_in_Dot">字体的高度，单位是dots</param>
        /// <param name="Str">输出的字符串</param>
        /// <param name="RotateDegree">字符串旋转的角度，0,90,180,270</param>
        private void PrintFontByPosition(int RefrenceX, int RefrenceY, int Width_in_Dot, int Height_in_Dot, string Str, int RotateDegree)
        {
                OutPutCode = OutPutCode + "^FO" + (RefrenceX * DPI / 300).ToString() + "," + (RefrenceY * DPI / 300).ToString();
                OutPutCode = OutPutCode + "^A0" + GetRotateCode(RotateDegree) + "," + (Height_in_Dot * DPI / 300).ToString() + "," + (Width_in_Dot * DPI / 300).ToString();
                OutPutCode = OutPutCode + "^FD" + Str;
                OutPutCode = OutPutCode + "^FS";
        }
        private void PrintFontByPosition(int RefrenceX, int RefrenceY, int Width_in_Dot, int Height_in_Dot, string Str, int RotateDegree,string font)
        {
            OutPutCode = OutPutCode + "^FO" + (RefrenceX * DPI / 300).ToString() + "," + (RefrenceY * DPI / 300).ToString();
            OutPutCode = OutPutCode + "^A"+font  + GetRotateCode(RotateDegree) + "," + (Height_in_Dot * DPI / 300).ToString() + "," + (Width_in_Dot * DPI / 300).ToString();
            OutPutCode = OutPutCode + "^FD" + Str;
            OutPutCode = OutPutCode + "^FS";
        }

        /// <summary> 输出一个中文
        /// </summary>
        private  void PrintCharatorByPosition(int RefrenceX, int RefrenceY, int Width_in_Dot, int Height_in_Dot, string Str, string FontName, int RotateDegree, int IsItalic, int IsBold)
        {
            int iRet;

            StringBuilder sb = new StringBuilder(204800);
            iRet = GETFONTHEX(Str, FontName, "CNFONT", RotateDegree, Height_in_Dot * DPI / 300, Width_in_Dot * DPI / 600, IsBold, IsItalic, sb);
            OutPutCode = OutPutCode + sb.ToString(); //download the Font to R:CNFONT.GRF
            OutPutCode = OutPutCode + string.Format("^FO{0},{1}^XGCNFONT,1,1^FS", (RefrenceX * DPI / 300).ToString(), (RefrenceY * DPI / 300).ToString());
            if (!this.CommPort.IsOpen) CommPort.Open();
            CommPort.Write(OutPutCode);
            CommPort.Close();
            OutPutCode = "";
        }
        
        /// <summary>输出矩形
        /// </summary>
        /// <param name="RefrenceX">起始点X坐标</param>
        /// <param name="RefrenceY">起始点Y坐标</param>
        /// <param name="Width">矩形的宽度</param>
        /// <param name="Height">矩形的高度</param>
        /// <param name="Thick">矩形的线宽</param>
        /// <param name="CornerDegree">圆角大小</param>
        private void PrintGraphBoxByPosition(int RefrenceX, int RefrenceY, int Width, int Height, int Thick, int CornerDegree)
        {
            //string sTemp = "";
            OutPutCode = OutPutCode + "^FO" + (RefrenceX * DPI / 300).ToString() + "," + (RefrenceY * DPI / 300).ToString();
            OutPutCode = OutPutCode + "^GB" + (Width * DPI / 300).ToString() + "," + (Height * DPI / 300).ToString() + "," + Thick.ToString() + ",B," + CornerDegree.ToString();
            OutPutCode = OutPutCode + "^FS";
            //return sTemp;
        }

        /// <summary>打印39条码
        /// </summary>
        /// <param name="RefrenceX">坐标X</param>
        /// <param name="RefrenceY">坐标Y</param>
        /// <param name="Width_in_Dot">细线的宽度，范围1，2,3，...10个dot</param>
        /// <param name="ratio">粗线与细线的比例，可选2,3</param>
        /// <param name="Height_in_Dot">条码的高度，单位是dot</param>
        /// <param name="Str">字串</param>
        /// <param name="RotateDegree">条码转动的角度，0,90,180,270</param>
        /// <param name="WetherPrintCode">是否将原码打印出来</param>
        /// <param name="PrintAboveBarCode">是否将原码打印在条码上面，一般选择False</param>
        private void PrintBarCode39(int RefrenceX, int RefrenceY, int Width_in_Dot, double ratio, int Height_in_Dot, string Str, int RotateDegree, bool WetherPrintCode, bool PrintAboveBarCode)
        {
            string strPrint;
            string strAboveCode;
            strPrint = (WetherPrintCode) ? "Y" : "N";
            strAboveCode = (PrintAboveBarCode) ? "Y" : "N";
            OutPutCode = OutPutCode + "^FO" + (RefrenceX * DPI / 300).ToString() + "," + (RefrenceY * DPI / 300).ToString();
            OutPutCode = OutPutCode + "^BY" + (Width_in_Dot * DPI / 300).ToString() + "," + ratio.ToString() + "," + (Height_in_Dot * DPI / 300).ToString();
            OutPutCode = OutPutCode + "^B3" + GetRotateCode(RotateDegree) + ",N," + (Height_in_Dot * DPI / 300).ToString() + "," + strPrint + "," + strAboveCode + "^FD" + Str;
            OutPutCode = OutPutCode + "^FS";
        }

        /// <summary>打印QR2维码
        /// </summary>
        /// <param name="RefrenceX">坐标X</param>
        /// <param name="RefrenceY">坐标Y</param>
        /// <param name="Width_in_Dot">细线的宽度，范围1，2,3，...10个dot</param>
        /// <param name="ratio">粗线与细线的比例，可选2,3</param>
        /// <param name="Height_in_Dot">条码的高度，单位是dot</param>
        /// <param name="Str">字串</param>
        /// <param name="RotateDegree">条码转动的角度，0,90,180,270</param>
        /// <param name="WetherPrintCode">是否将原码打印出来</param>
        /// <param name="PrintAboveBarCode">是否将原码打印在条码上面，一般选择False</param>
        private void Print2DCode_QR(int RefrenceX, int RefrenceY, int Width_in_Dot, double ratio, int Height_in_Dot, string Str, int RotateDegree, bool WetherPrintCode, bool PrintAboveBarCode)
        {
            string strPrint;
            string strAboveCode;
            strPrint = (WetherPrintCode) ? "Y" : "N";
            strAboveCode = (PrintAboveBarCode) ? "Y" : "N";
            OutPutCode = OutPutCode + "^FO" + (RefrenceX * DPI / 300).ToString() + "," + (RefrenceY * DPI / 300).ToString();
            //OutPutCode = OutPutCode + "^BY" +  (Width_in_Dot * DPI / 300).ToString() + "," + ratio.ToString() + "," + (Height_in_Dot * DPI / 300).ToString();
            OutPutCode = OutPutCode + "^BQN,2," + Width_in_Dot + "^FDQA," + Str;
            OutPutCode = OutPutCode + "^FS";
        }

        /// <summary>打印EAN-8条码
        /// </summary>
        /// <param name="RefrenceX">坐标X</param>
        /// <param name="RefrenceY">坐标Y</param>
        /// <param name="Width_in_Dot">细线的宽度，范围1，2,3，...10个dot</param>
        /// <param name="ratio">粗线与细线的比例，可选2,3</param>
        /// <param name="Height_in_Dot">条码的高度，单位是dot</param>
        /// <param name="Str">字串</param>
        /// <param name="RotateDegree">条码转动的角度，0,90,180,270</param>
        /// <param name="WetherPrintCode">是否将原码打印出来</param>
        /// <param name="PrintAboveBarCode">是否将原码打印在条码上面，一般选择False</param>
        private void PrintBarCodeEAN_8(int RefrenceX, int RefrenceY, int Width_in_Dot, double ratio, int Height_in_Dot, string Str, int RotateDegree, bool WetherPrintCode, bool PrintAboveBarCode)
        {
            string strPrint;
            string strAboveCode;
            strPrint = (WetherPrintCode) ? "Y" : "N";
            strAboveCode = (PrintAboveBarCode) ? "Y" : "N";
            OutPutCode = OutPutCode + "^FO" + (RefrenceX * DPI / 300).ToString() + "," + (RefrenceY * DPI / 300).ToString();
            OutPutCode = OutPutCode + "^BY" + (Width_in_Dot * DPI / 300).ToString() + "," + ratio.ToString() + "," + (Height_in_Dot * DPI / 300).ToString();
            OutPutCode = OutPutCode + "^B8" + GetRotateCode(RotateDegree) + (Height_in_Dot * DPI / 300).ToString() + "," + strPrint + "," + strAboveCode + "^FD" + Str;
            OutPutCode = OutPutCode + "^FS";
        }

        /// <summary>打印128条码
        /// </summary>
        /// <param name="RefrenceX">坐标X</param>
        /// <param name="RefrenceY">坐标Y</param>
        /// <param name="Width_in_Dot">细线的宽度，范围1，2,3，...10个dot</param>
        /// <param name="ratio">粗线与细线的比例，可选2,3</param>
        /// <param name="Height_in_Dot">条码的高度，单位是dot</param>
        /// <param name="Str">字串</param>
        /// <param name="RotateDegree">条码转动的角度，0,90,180,270</param>
        /// <param name="WetherPrintCode">是否将原码打印出来</param>
        /// <param name="PrintAboveBarCode">是否将原码打印在条码上面，一般选择False</param>
        private void PrintBarCode128(int RefrenceX, int RefrenceY, int Width_in_Dot, double ratio, int Height_in_Dot, string Str, int RotateDegree, bool WetherPrintCode, bool PrintAboveBarCode)
        {
            string strPrint;
            string strAboveCode;
            strPrint = (WetherPrintCode) ? "Y" : "N";
            strAboveCode = (PrintAboveBarCode) ? "Y" : "N";
            OutPutCode = OutPutCode + "^FO" + (RefrenceX * DPI / 300).ToString() + "," + (RefrenceY * DPI / 300).ToString();
            OutPutCode = OutPutCode + "^BY" + (Width_in_Dot * DPI / 300).ToString() + "," + ratio.ToString() + "," + (Height_in_Dot * DPI / 300).ToString();
            OutPutCode = OutPutCode + "^BC" + GetRotateCode(RotateDegree) + (Height_in_Dot * DPI / 300).ToString() + "," + strPrint + "," + strAboveCode + "^FD" + Str;
            OutPutCode = OutPutCode + "^FS";
        }

        /// <summary>打印二维码Data Matrix
        /// </summary>
        /// <param name="RefrenceX">位置X</param>
        /// <param name="RefrenceY">位置Y</param>
        /// <param name="Str">字串</param>
        /// <param name="Height_in_Dot">每个小方格的高度，最小为1</param>
        /// <param name="Quality">用于二维码生成时，加入的防错数据，可选值0, 50, 80, 100, 140, 200</param>
        /// <param name="RotateDegree">旋转角度，可选0,90,180,270</param>
        private void PrintDataMatrix(int RefrenceX, int RefrenceY, string Str, int Height_in_Dot, int Quality, int RotateDegree)
        {
            OutPutCode = OutPutCode + "^FO" + (RefrenceX * DPI / 300).ToString() + "," + (RefrenceY * DPI / 300).ToString();
            OutPutCode = OutPutCode + "^BX" + this.GetRotateCode(RotateDegree) + "," + (Height_in_Dot * DPI / 300).ToString() + "," + Quality.ToString() + "^FD" + Str;
            OutPutCode = OutPutCode + "^FS";
        }
        

        [DllImport("Fnthex32.dll")]
        public static extern int GETFONTHEX(string BarcodeText, string FontName, string FileName, int Orient, int Height, int Width, int IsBold, int IsItalic, StringBuilder ReturnBarcodeCMD);
        
        #endregion



       
    }

    /// <summary>标签类，创建标签后，自动将Label.ini的配置读取至标签的文本条目和框框。其中的LabelText[]和LabelBox[]是Public，其内容可以直接在外部编辑
    /// </summary>
    public class ZebraLabel
    {
        private INIClass myINI;
        private string LabelINI;

        #region --------label setting-----

        public LabelBox[] lbBox = new LabelBox[] { };//id从1到QtyOfBox,
        private int QtyOfBox;
        public LabelText[] lbText = new LabelText[] { };
        private int QtyOfText;
        #endregion

        /// <summary>构造函数，创建ZebraLabel之后就读取Label.ini的配置内容
        /// </summary>
        public ZebraLabel()
        {
            LabelINI = Application.StartupPath + "\\Label.ini";
            myINI = new INIClass(LabelINI);
            ID_All_ReadFromINI();
        }
        /// <summary>构造函数，创建ZebraLabel之后就读取Label.ini的配置内容
        /// </summary>
        public ZebraLabel(string iniPath)
        {
            LabelINI = iniPath;
            myINI = new INIClass(LabelINI);
            ID_All_ReadFromINI();
        }

        #region -------Functions of Text & Box Read/Write from INI with ID-------------
        /// <summary>子功能，把标签中的第id个文本的参数写入Label.ini中的[TEXT+id]段
        /// </summary>
        private void WriteTextParasToINI(LabelText lb, int id)
        {
            if (id < 0)
            {
                MessageBox.Show("ZebraLabel.WriteTextParasToINI()函数错误，参数id小于0！");
            }
            else
            {
                myINI.IniWriteValue("TEXT" + id.ToString(), "Name", lb.Name);
                myINI.IniWriteValue("TEXT" + id.ToString(), "NamePosX", lb.NamePosX.ToString());
                myINI.IniWriteValue("TEXT" + id.ToString(), "BarPosX", lb.BarPosX.ToString());
                myINI.IniWriteValue("TEXT" + id.ToString(), "NameFontCN", lb.NameFontCN);

                myINI.IniWriteValue("TEXT" + id.ToString(), "NamePosY", lb.NamePosY.ToString());
                myINI.IniWriteValue("TEXT" + id.ToString(), "BarPosY", lb.BarPosY.ToString());

                myINI.IniWriteValue("TEXT" + id.ToString(), "NameHeight", lb.NameHeight.ToString());
                myINI.IniWriteValue("TEXT" + id.ToString(), "TextHeight", lb.TextHeight.ToString());
                myINI.IniWriteValue("TEXT" + id.ToString(), "BarHeight", lb.BarHeight.ToString());

                myINI.IniWriteValue("TEXT" + id.ToString(), "NameWidth", lb.NameWidth.ToString());
                myINI.IniWriteValue("TEXT" + id.ToString(), "TextWidth", lb.TextWidth.ToString());
                myINI.IniWriteValue("TEXT" + id.ToString(), "BarWidth", lb.BarWidth.ToString());

                myINI.IniWriteValue("TEXT" + id.ToString(), "RotateDegree", lb.RotateDegree.ToString());
                myINI.IniWriteValue("TEXT" + id.ToString(), "BarRation", lb.BarRatio.ToString());

                myINI.IniWriteValue("TEXT" + id.ToString(), "PrintName", lb.PrintName.ToString());
                myINI.IniWriteValue("TEXT" + id.ToString(), "PrintBar", lb.PrintBar.ToString());
                myINI.IniWriteValue("TEXT" + id.ToString(), "PrintCode", lb.PrintCode.ToString());
                myINI.IniWriteValue("TEXT" + id.ToString(), "PrintAboveBarCode", lb.PrintAboveBarCode.ToString());

                myINI.IniWriteValue("TEXT" + id.ToString(), "TextPosX", lb.TextPosX.ToString());
                myINI.IniWriteValue("TEXT" + id.ToString(), "TextPosY", lb.TextPosY.ToString());
                myINI.IniWriteValue("TEXT" + id.ToString(), "TextFontCN", lb.TextFontCN);
                myINI.IniWriteValue("TEXT" + id.ToString(), "BarType", lb.BarType.ToString());
                myINI.IniWriteValue("TEXT" + id.ToString(), "PrintText", lb.PrintText.ToString());
                myINI.IniWriteValue("TEXT" + id.ToString(), "NameTextTogether", lb.NameTextTogether.ToString());

                myINI.IniWriteValue("TEXT" + id.ToString(), "NameFont", lb.NameFont.ToString());
                myINI.IniWriteValue("TEXT" + id.ToString(), "TextFont", lb.TextFont.ToString());
            }
        }

        /// <summary>子功能，将标签中的第id个框框的参数写入Label.ini中的[BOX+id]段
        /// </summary>
        private void WriteBoxParasToINI(LabelBox lb, int id)
        {
            if (id < 0)
            {
                MessageBox.Show("ZebraLabel.WriteBoxParasToINI()函数错误，参数id小于0");
            }
            else
            {
                myINI.IniWriteValue("BOX" + id.ToString(), "PosX", lb.PosX.ToString());
                myINI.IniWriteValue("BOX" + id.ToString(), "PosY", lb.PosY.ToString());
                myINI.IniWriteValue("BOX" + id.ToString(), "Height", lb.Height.ToString());
                myINI.IniWriteValue("BOX" + id.ToString(), "Width", lb.Width.ToString());
                myINI.IniWriteValue("BOX" + id.ToString(), "Thick", lb.Thick.ToString());
                myINI.IniWriteValue("BOX" + id.ToString(), "Corner", lb.Corner.ToString());
            }
        }

        /// <summary>子功能，从Label.ini中读取第id个文本条目的参数
        /// </summary>
        private LabelText ReadTextParasFromINI(int id)
        {
            LabelText lbTemp = new LabelText();
            if (id < 0)
            {
                MessageBox.Show("ZebraLabel.ReadTextParasFromINI()函数错误，参数id小于0！");
                return lbTemp;
            }
            else
            {
                lbTemp.Name = myINI.IniReadValue("TEXT" + id.ToString(), "Name", "Text" + id.ToString());
                lbTemp.NamePosX = myINI.IniReadValue("TEXT" + id.ToString(), "NamePosX", -1);
                lbTemp.BarPosX = myINI.IniReadValue("TEXT" + id.ToString(), "BarPosX", lbTemp.NamePosX);
                lbTemp.NameFontCN = myINI.IniReadValue("TEXT" + id.ToString(), "NameFontCN", "Arial");

                lbTemp.NamePosY = myINI.IniReadValue("TEXT" + id.ToString(), "NamePosY", -1);
                lbTemp.BarPosY = myINI.IniReadValue("TEXT" + id.ToString(), "BarPosY", lbTemp.NamePosY);

                lbTemp.NameHeight = myINI.IniReadValue("TEXT" + id.ToString(), "NameHeight", -1);
                lbTemp.BarHeight = myINI.IniReadValue("TEXT" + id.ToString(), "BarHeight", -1);

                lbTemp.NameWidth = myINI.IniReadValue("TEXT" + id.ToString(), "NameWidth", -1);
                lbTemp.TextWidth = myINI.IniReadValue("TEXT" + id.ToString(), "TextWidth", -1);
                lbTemp.BarWidth = myINI.IniReadValue("TEXT" + id.ToString(), "BarWidth", -1);

                lbTemp.RotateDegree = myINI.IniReadValue("TEXT" + id.ToString(), "RotateDegree", -1);
                lbTemp.TextHeight = myINI.IniReadValue("TEXT" + id.ToString(), "TextHeight", -1);
                lbTemp.BarRatio = myINI.IniReadValue("TEXT" + id.ToString(), "BarRatio", 1);

                lbTemp.PrintName = myINI.IniReadValue("TEXT" + id.ToString(), "PrintName", true);
                lbTemp.PrintBar = myINI.IniReadValue("TEXT" + id.ToString(), "PrintBar", true);
                lbTemp.PrintCode = myINI.IniReadValue("TEXT" + id.ToString(), "PrintCode", true);
                lbTemp.PrintAboveBarCode = myINI.IniReadValue("TEXT" + id.ToString(), "PrintAboveBarCode", false);

                lbTemp.TextPosX = myINI.IniReadValue("TEXT" + id.ToString(), "TextPosX", -1);
                lbTemp.TextPosY = myINI.IniReadValue("TEXT" + id.ToString(), "TextPosY", -1);
                lbTemp.TextFontCN = myINI.IniReadValue("TEXT" + id.ToString(), "TextFontCN", "Arial");

                lbTemp.BarType = myINI.IniReadValue("TEXT" + id.ToString(), "BarType", 0);
                lbTemp.PrintText = myINI.IniReadValue("TEXT" + id.ToString(), "PrintText", true);
                lbTemp.NameTextTogether = myINI.IniReadValue("TEXT" + id.ToString(), "NameTextTogether", true);

                lbTemp.NameFont = myINI.IniReadValue("TEXT" + id.ToString(), "NameFont", "D");
                lbTemp.TextFont = myINI.IniReadValue("TEXT" + id.ToString(), "TextFont", "D");

                lbTemp.Text = "";
                return lbTemp;
            }
        }

        /// <summary>子功能，从Label.ini中读取第id个框框的参数
        /// </summary>
        private LabelBox ReadBoxParasFromINI(int id)
        {
            LabelBox lbTemp = new LabelBox();
            if (id < 0)
            {
                MessageBox.Show("ZebraLabel.ReadBoxParasFromINI()函数错误，参数id小于0！");
                // new LogWrite("ID_Single_ReadBoxParasFromINI函数的ID 错误！", myCommon);
                return lbTemp;
            }
            else
            {
                lbTemp.PosX = myINI.IniReadValue("BOX" + id.ToString(), "PosX", -1);
                lbTemp.PosY = myINI.IniReadValue("BOX" + id.ToString(), "PosY", -1);
                lbTemp.Height = myINI.IniReadValue("BOX" + id.ToString(), "Height", -1);
                lbTemp.Width = myINI.IniReadValue("BOX" + id.ToString(), "Width", -1);
                lbTemp.Thick = myINI.IniReadValue("BOX" + id.ToString(), "Thick", -1);
                lbTemp.Corner = myINI.IniReadValue("BOX" + id.ToString(), "Corner", -1);
                return lbTemp;
            }
        }

        /// <summary>为某个文本对象设定内容，即名字为TextName的lbText的Text内容赋值为value
        /// </summary>
        private void ID_Single_SetText(string TextName, string value)
        {
            int id;
            id = myINI.CheckExistInINI("General", "QtyOfText", TextName);
            if (id < 0) MessageBox.Show(string.Format("ZebraLabel.ID_Single_SetText()函数错误，没有找到名为{0}的文本条目", TextName));
            else
            {
                lbText[id].Text = value;
            }
        }

        /// <summary>获取标签内名为TextName的文本条目的文本内容
        /// </summary>
        private string ID_Single_GetText(string TextName)
        {
            int id;
            id = myINI.CheckExistInINI("General", "QtyOfText", TextName);
            if (id < 0)
            {
                MessageBox.Show(string.Format("ZebraLabel.ID_Single_GetText()错误，没有找到名为{0}的文本条目", TextName));
                return "ERROR";
            }
            else
            {
                return lbText[id].Text;
            }
        }

        /// <summary>从Label.ini中读取所有的文本条目和框框
        /// </summary>
        public void ID_All_ReadFromINI()
        {
            int i;
            INIClass myINI = new INIClass(LabelINI);
            QtyOfText = myINI.IniReadValue("General", "QtyOfText", 1);//文本条目的总数
            QtyOfBox = myINI.IniReadValue("General", "QtyOfBox", 1);//框框的总数
            lbText = new LabelText[QtyOfText];//创建文本条目
            lbBox = new LabelBox[QtyOfBox];//创建框框

            for (i = 0; i < QtyOfText; i++)
            {
                lbText[i] = ReadTextParasFromINI(i);//读取文本条目的配置
            }
            for (i = 0; i < QtyOfBox; i++)
            {
                lbBox[i] = ReadBoxParasFromINI(i);//读取框框的配置
            }
        }

        /// <summary>将文本条目和框框的配置写入Label.ini中
        /// </summary>
        public void ID_All_WriteToINI()
        {
            int i;
            INIClass myINI = new INIClass(LabelINI);
            myINI.IniWriteValue("General", "QtyOfText", QtyOfText.ToString());//写入所有文本条目的总数
            myINI.IniWriteValue("General", "QtyOfBox", QtyOfBox.ToString());//写入所有框框的总数

            for (i = 0; i < QtyOfText; i++)//写入所有文本条目的配置
            {
                myINI.IniWriteValue("General", i.ToString(), lbText[i].Name);
                WriteTextParasToINI(lbText[i], i);
            }
            for (i = 0; i < QtyOfBox; i++)//写入所有框框的配置
            {
                WriteBoxParasToINI(lbBox[i], i);
            }
        }

        public DataTable[] ConvertToDataTable(ZebraLabel lb)
        {
            int i;
            DataTable dt_text = new System.Data.DataTable();
            DataTable dt_box = new System.Data.DataTable();

            dt_text.Columns.Add("Nr",typeof (int));
            dt_text.Columns.Add("Name");
            dt_text.Columns.Add("Text");
            dt_text.Columns.Add("NamePosX");
            dt_text.Columns.Add("NamePosY");
            dt_text.Columns.Add("TextPosX");
            dt_text.Columns.Add("TextPosY");
            dt_text.Columns.Add("NameWidth");
            dt_text.Columns.Add("NameHeight");
            dt_text.Columns.Add("TextWidth");
            dt_text.Columns.Add("TextHeight");
            dt_text.Columns.Add("RotateDegree");
            dt_text.Columns.Add("PrintBar");
            dt_text.Columns.Add("PrintName");
            dt_text.Columns.Add("BarType");
            dt_text.Columns.Add("BarPosX");
            dt_text.Columns.Add("BarPosY");
            dt_text.Columns.Add("BarWidth");
            dt_text.Columns.Add("BarHeight");
            dt_text.Columns.Add("BarRatio");
            dt_text.Columns.Add("PrintCode");
            dt_text.Columns.Add("PrintAboveBarCode");
            dt_text.Columns.Add("PrintText");
            dt_text.Columns.Add("NameTextTogether");
            dt_text.Columns.Add("NameFont");
            dt_text.Columns.Add("TextFont");
            dt_text.Columns.Add("NameFontCN");
            dt_text.Columns.Add("TextFontCN");

            for (i = 0; i < lb.lbText.Length; i++)
            {
                dt_text.Rows.Add(new object[28] {
                    i,
                    lb.lbText[i].Name.ToString(),
                    lb.lbText[i].Text.ToString(),
                    lb.lbText[i].NamePosX.ToString(),
                    lb.lbText[i].NamePosY.ToString(),
                    lb.lbText[i].TextPosX.ToString(),
                    lb.lbText[i].TextPosY.ToString(),
                    lb.lbText[i].NameWidth.ToString(),
                    lb.lbText[i].NameHeight.ToString(),
                    lb.lbText[i].TextWidth.ToString(),
                    lb.lbText[i].TextHeight.ToString(),
                    lb.lbText[i].RotateDegree.ToString(),
                    lb.lbText[i].PrintBar.ToString(),
                    lb.lbText[i].PrintName.ToString(),
                    lb.lbText[i].BarType.ToString(),
                    lb.lbText[i].BarPosX.ToString(),
                    lb.lbText[i].BarPosY.ToString(),
                    lb.lbText[i].BarWidth.ToString(),
                    lb.lbText[i].BarHeight.ToString(),
                    lb.lbText[i].BarRatio.ToString(),
                    lb.lbText[i].PrintCode.ToString(),
                    lb.lbText[i].PrintAboveBarCode.ToString(),
                    lb.lbText[i].PrintText.ToString(),
                    lb.lbText[i].NameTextTogether.ToString(),
                    lb.lbText[i].NameFont.ToString(),
                    lb.lbText[i].TextFont.ToString(),
                    lb.lbText[i].NameFontCN.ToString(),
                    lb.lbText[i].TextFontCN.ToString()

                });
            }
            dt_box .Columns.Add("Nr",typeof (int));
                dt_box.Columns.Add("Description");
                dt_box.Columns.Add("PosX");
                dt_box.Columns.Add("PosY");
                dt_box.Columns.Add("Width");
                dt_box.Columns.Add("Height");
                dt_box.Columns.Add("Thick");
                dt_box.Columns.Add("Corner");

                for (i = 0; i < lb.lbBox.Length; i++)
            {
                dt_box.Rows.Add(new object[8] {
                    i,
                    (lb.lbBox [i].Description==null )?"":lb.lbBox [i].Description,
                    lb.lbBox [i].PosX.ToString (),
                    lb.lbBox [i].PosY.ToString (),
                    lb.lbBox [i].Width .ToString (),
                    lb.lbBox[i].Height .ToString (),
                    lb.lbBox[i].Thick .ToString (),
                    lb.lbBox [i].Corner .ToString ()
                });

            }
            return new DataTable[] { dt_text, dt_box };


        }
        public DataTable[] ConvertToDataTable()
        {
            return ConvertToDataTable(this);
        }

        public void ReadLabelFromDataTable(DataTable[] dt)
        {
            int i;
            for (i = 0; i < dt[0].Rows.Count; i++)
            {
                lbText[i].Name = dt[0].Rows[i]["Name"].ToString ();
                lbText[i].Text = dt[0].Rows[i]["Text"].ToString ();
                lbText[i].NamePosX = Convert .ToInt32 ( dt[0].Rows[i]["NamePosX"]);
                lbText[i].NamePosY =Convert .ToInt32 ( dt[0].Rows[i]["NamePosY"]);
                lbText[i].TextPosX = Convert .ToInt32 (dt[0].Rows[i]["TextPosX"]);
                lbText[i].TextPosY = Convert .ToInt32 (dt[0].Rows[i]["TextPosY"]);
                lbText[i].NameWidth =Convert .ToInt32 ( dt[0].Rows[i]["NameWidth"]);
                lbText[i].NameHeight =Convert .ToInt32 (dt[0].Rows[i]["NameHeight"]);
                lbText[i].TextWidth =Convert .ToInt32 ( dt[0].Rows[i]["TextWidth"]);
                lbText[i].TextHeight =Convert .ToInt32 (dt[0].Rows[i]["TextHeight"]);
                lbText[i].RotateDegree = Convert .ToInt32 (dt[0].Rows[i]["RotateDegree"]);
                lbText[i].PrintBar =Convert .ToBoolean  ( dt[0].Rows[i]["PrintBar"]);
                lbText[i].PrintName =Convert .ToBoolean  ( dt[0].Rows[i]["PrintName"]);
                lbText[i].BarType =Convert .ToInt32  ( dt[0].Rows[i]["BarType"]);
                lbText[i].BarPosX =Convert .ToInt32  ( dt[0].Rows[i]["BarPosX"]);
                lbText[i].BarPosY =Convert .ToInt32 ( dt[0].Rows[i]["BarPosY"]);
                lbText[i].BarWidth =Convert .ToInt32 ( dt[0].Rows[i]["BarWidth"]);
                lbText[i].BarHeight = Convert .ToInt32 (dt[0].Rows[i]["BarHeight"]);
                lbText[i].BarRatio = Convert .ToInt32 (dt[0].Rows[i]["BarRatio"]);
                lbText[i].PrintCode =Convert .ToBoolean  ( dt[0].Rows[i]["PrintCode"]);
                lbText[i].PrintAboveBarCode =Convert .ToBoolean  ( dt[0].Rows[i]["PrintAboveBarCode"]);
                lbText[i].PrintText =Convert .ToBoolean  ( dt[0].Rows[i]["PrintText"]);
                lbText[i].NameTextTogether =Convert .ToBoolean  ( dt[0].Rows[i]["NameTextTogether"]);
                lbText[i].NameFont = dt[0].Rows[i]["NameFont"].ToString ();
                lbText[i].TextFont = dt[0].Rows[i]["TextFont"].ToString ();
                lbText[i].NameFontCN = dt[0].Rows[i]["NameFontCN"].ToString ();
                lbText[i].TextFontCN = dt[0].Rows[i]["TextFontCN"].ToString ();

            }
            QtyOfText = lbText.Length;

            for (i = 0; i < dt[1].Rows.Count; i++)
            {
                lbBox[i].Description =(string) dt[1].Rows[i]["Description"];
                lbBox[i].PosX =Convert .ToInt32 ( dt[1].Rows[i]["PosX"]);
                lbBox[i].PosY =Convert .ToInt32 ( dt[1].Rows[i]["PosY"]);
                lbBox[i].Width = Convert .ToInt32 ( dt[1].Rows[i]["Width"]);
                lbBox[i].Height = Convert .ToInt32 ( dt[1].Rows[i]["Height"]);
                lbBox[i].Thick = Convert .ToInt32 ( dt[1].Rows[i]["Thick"]);
                lbBox[i].Corner = Convert .ToInt32 ( dt[1].Rows[i]["Corner"]);
            }
            QtyOfBox = lbBox.Length;
            
        }
        public void AppendLabelText()
        {
            Array.Resize<LabelText>(ref lbText, lbText.Length + 1);
            lbText[lbText.Length-1].Text  = "NewAdded";
            lbText[lbText.Length - 1].Name  = "NewAdded";
            lbText[lbText.Length - 1].NameFont  = "0";
            lbText[lbText.Length - 1].NameFontCN = "0";
            lbText[lbText.Length - 1].TextFont = "0";
            lbText[lbText.Length - 1].TextFontCN  = "0";
            
        }
        #endregion


    }
}